package com.higgins.eventtracking.server;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.higgins.eventtracking.client.dto.GoalDTO;
import com.higgins.eventtracking.client.dto.HealthAlertDTO;
import com.higgins.eventtracking.client.dto.HealthEventDTO;
import com.higgins.eventtracking.client.dto.RuleDTO;
import com.higgins.eventtracking.client.dto.SupportDTO;
import com.higgins.eventtracking.client.dto.TimeTableTaskDTO;
import com.higgins.eventtracking.client.dto.TrackingEventDTO;
import com.higgins.eventtracking.client.dto.TransactionDTO;
import com.higgins.eventtracking.client.dto.WeightEventDTO;
import com.higgins.eventtracking.server.dataModel.BodyStats;
import com.higgins.eventtracking.server.dataModel.Consumption;
import com.higgins.eventtracking.server.dataModel.FrameOfMind;
import com.higgins.eventtracking.server.dataModel.Goal;
import com.higgins.eventtracking.server.dataModel.HealthAlert;
import com.higgins.eventtracking.server.dataModel.HealthEvent;
import com.higgins.eventtracking.server.dataModel.Rule;
import com.higgins.eventtracking.server.dataModel.Support;
import com.higgins.eventtracking.server.dataModel.TimeTableTask;
import com.higgins.eventtracking.server.dataModel.TrackingEvent;
import com.higgins.eventtracking.server.dataModel.Transaction;
import com.higgins.eventtracking.server.dataModel.WeightEvent;

public class DataStoreService {
	protected PersistenceManager pm;
	
	public void openPersistenceManager()	{
		pm=PMF.get().getPersistenceManager();
	}
	public void closePersistenceManager()	{
		pm.close();
	}
	
	/*
	 * not yet needed
	@SuppressWarnings("unchecked")
	public List<EventType> retrieveExercises()	{
		List<EventType> results; 
		Query query;
		query=pm.newQuery(EventType.class);
		results = (List<EventType>) query.execute();
		return results;
	}		
	
	public Boolean insertExercise(EventType eventType)	{
		Boolean success = true;
		try	{
			pm.makePersistent(eventType);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	public Boolean deleteExercise(EventType eventType)	{
		Boolean success = true;
		try	{
			if (eventType!=null)	{
				Query query=pm.newQuery(EventType);
				query.setFilter("name==nameParam");
				query.declareParameters("String nameParam");
				query.deletePersistentAll(eventType.getName());
			} 
		} catch (Exception e)	{
			success = false;
		}
		return success;
	}		*/

	

	
	@SuppressWarnings("unchecked")
	public TrackingEvent retrieveBestTrackingEvent(String trackingEventType)	{
		Date date = DateUtility.getStartOfWeeksAgo(new Date(), 5);
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("eventType==nameParam && timestamp >= dateParam");
		query.declareParameters("String nameParam, java.util.Date dateParam");		
		results = (List<TrackingEvent>) query.execute(trackingEventType, date);
		int size = results.size();
		
		TrackingEvent returnEvent = null;
		if (trackingEventType.equals("Walking")||trackingEventType.equals("Cycling")||trackingEventType.equals("Running")||trackingEventType.equals("Swimming"))			{
			Double distance = 0.0;
			for (TrackingEvent event:results)	{
				if (event.getDistance() > distance)	{
					returnEvent = event;
				}
			}
		} else	{
			Double weight = 0.0;
			for (TrackingEvent event:results)	{
				if (event.getWeight() > weight)	{
					returnEvent = event;
				}
			}
		}

		
		return (size > 0)?returnEvent:null;
	}
	
	@SuppressWarnings("unchecked")
	public List<TrackingEvent> retrieveTrackingEvents(String trackingEventType)	{
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		if (trackingEventType!=null)	{
			query.setFilter("eventType==nameParam");
			query.declareParameters("String nameParam");
			query.setOrdering("timestamp desc");
			results = (List<TrackingEvent>) query.execute(trackingEventType);
		} else {
			query.setOrdering("timestamp desc");
			results = (List<TrackingEvent>) query.execute();
		}
		return results;
	}
	
	public List<TrackingEvent> retrieveTrackingEvents(Date start, Date end)	{
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("timestamp>=startParam && timestamp<=endParam");
		query.declareParameters("java.util.Date startParam, java.util.Date endParam");
		query.setOrdering("timestamp desc");
		results = (List<TrackingEvent>) query.execute(start, end);
		return results;
	}
	
	public Boolean insertFrameOfMind(String frameOfMindName) {
		FrameOfMind frameOfMind = new FrameOfMind();
		frameOfMind.setFrameOfMindName(frameOfMindName);
		frameOfMind.setTimestamp(new Date());
		
		Boolean success = true;
		try	{
			pm.makePersistent(frameOfMind);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	public Boolean frameOfMindSetToday() {
		Date startDate = DateUtility.addHours(new Date(), -1);
		Date endDate = new Date();
		Query query;
		query=pm.newQuery(FrameOfMind.class);
		query.setFilter("timestamp > startDate && timestamp < endDate");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate");
		query.setOrdering("timestamp desc");
		List<FrameOfMind> results = (List<FrameOfMind>) query.execute(startDate, endDate);
		return results.size() > 0;
	}
	
	public Boolean weightEventToday(String weightEventType)	{
		Date startDate = DateUtility.addDays(new Date(), -7);
		Date endDate = new Date();
		Query query;
		query=pm.newQuery(WeightEvent.class);
		query.setFilter("timestamp > startDate && timestamp < endDate && weightEventType == weightEventName");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate, String weightEventName"); 
		query.setOrdering("timestamp desc");
		List<WeightEvent> results = (List<WeightEvent>) query.execute(startDate, endDate, weightEventType);
		return results.size() > 0;
	}

	public HealthEvent retrieveCurrentHealthEvent(String healthEventType)	{
		Date startDate = DateUtility.addDays(new Date(), -2);
		Date endDate = new Date();
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("timestamp > startDate && timestamp < endDate && healthEventType == healthEventName");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate, String healthEventName"); 
		query.setOrdering("timestamp desc");
		List<HealthEvent> results = (List<HealthEvent>) query.execute(startDate, endDate, healthEventType);
		if (results.size() > 0)	{
			return results.get(0);
		} else {
			return null;
		}
	}
	public Boolean healthEventToday(String healthEventType)	{
		Date startDate = DateUtility.addHours(new Date(), -1);
		Date endDate = new Date();
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("timestamp > startDate && timestamp < endDate && healthEventType == healthEventName");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate, String healthEventName"); 
		query.setOrdering("timestamp desc");
		List<HealthEvent> results = (List<HealthEvent>) query.execute(startDate, endDate, healthEventType);
		return results.size() > 0;
	}
	public Boolean insertTrackingEvent(TrackingEvent trackingEvent)	{
		Boolean success = true;
		try	{
			pm.makePersistent(trackingEvent);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	
	public Boolean deleteTrackingEvents(String trackingEventType)	{
		Boolean success = true;
		try	{
			if (trackingEventType!=null)	{
				Query query=pm.newQuery(TrackingEvent.class);
				query.setFilter("eventType==nameParam");
				query.declareParameters("String nameParam");
				query.deletePersistentAll(trackingEventType);
			} 
		} catch (Exception e)	{
			success = false;
		}
		return success;
	}
	
	
	
	
	
	
	
	public Boolean insertTransaction(TransactionDTO transactionDTO)	{
		Transaction transaction = new Transaction(transactionDTO);
		Boolean success = true;
		try	{
			pm.makePersistent(transaction);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	/*
	public Double getTotalSpentThisWeek()	{
		Date now = new Date();
		Date monday = getStartOfWeekDate(now).getTime();
		return retrieveTotalSpend(monday, new Date());
	}	*/
	/*
	public Double getAverageMonthlySpentThisMonth()	{
		Date now = new Date();
		int numberOfWeeksInMonth = getNumberOfWeeksInMonth();
		double averageWeeklySpend = getAverageWeeklySpentThisMonth();
		return (averageWeeklySpend * numberOfWeeksInMonth);
	}	*/
	/*
	public Double getAverageWeeklySpentThisMonth()	{
		Date now = new Date();
		Date startOfMonth = getStartOfMonthDate(now).getTime();
		Date startOfWeek = getStartOfWeekDate(now).getTime();
		Double totalSpendThisMonth = retrieveTotalSpend(startOfMonth, startOfWeek);
		if (totalSpendThisMonth < 100.0)	{
			return getAverageWeeklySpentLastMonth();
		} else {
			int weekNumber = getWeekNumber(now) - 1;
			return  totalSpendThisMonth/ weekNumber;
		}
	}	*/
	/*
	public Double getAverageWeeklySpentLastMonth()	{
		Calendar cal = Calendar.getInstance();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		cal.add(Calendar.MONTH, -1);

		Date startOfMonth = getStartOfMonth(cal.get(Calendar.MONTH));
		Date endOfMonth = getEndOfMonth(cal.get(Calendar.MONTH));
		int numberOfWeeksInMonth = getNumberOfWeeksLastMonth();
		
		Double totalSpendLastMonth = retrieveTotalSpend(startOfMonth, endOfMonth);
		
		return totalSpendLastMonth/numberOfWeeksInMonth;
	}		*/
	public Integer getWeekNumber(Date now)	{
		Calendar cal = getStartOfWeekDate(now);
		int days = cal.get(Calendar.DATE);
		
		days+=2;
		Integer numberOfWeeks = days/7;
		return numberOfWeeks + 1;
	}

	public Integer getNumberOfWeeksInMonth(Date now)	{
		Calendar calNow = Calendar.getInstance();
		calNow.setTime(now);
		calNow.add(Calendar.DAY_OF_MONTH, 2);
		
		
		Calendar calStartOfThisMonth = getStartOfMonthDate(calNow.getTime());
		
		Calendar calNextMonth = Calendar.getInstance();
		calNextMonth.setTime(calNow.getTime());
		calNextMonth.add(Calendar.MONTH, 1);
		
		Calendar calStartOfNextMonth = getStartOfMonthDate(calNextMonth.getTime());
		
		long difference = calStartOfNextMonth.getTimeInMillis() - calStartOfThisMonth.getTimeInMillis();
		long seconds = difference/1000;
		long minutes = seconds /60;
		long hours = minutes / 60;
		long daysOfMonth = hours/24;
		
		Integer numberOfWeeks = (int) (daysOfMonth/7);
		return numberOfWeeks;
	}
	
	
	private Calendar getStartOfWeekDate(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		int numberOfDays = cal.get(Calendar.DAY_OF_WEEK) > 1?(cal.get(Calendar.DAY_OF_WEEK)-2):6;
		cal.add(Calendar.DATE, -numberOfDays);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
		return cal;
	}
	private Calendar getStartOfMonthDate(Date now)	{
		Calendar cal = getStartOfWeekDate(now);
		int days = cal.get(Calendar.DATE);
		
		days+=2;
		Integer numberOfWeeks = days/7;
		
		cal.add(Calendar.DATE, -(numberOfWeeks*7));
		return cal;
	}
	private Calendar getStartOfDay(Calendar cal)	{
		Calendar localCal = (Calendar)cal.clone();
		localCal.set(Calendar.HOUR_OF_DAY, 0);
		localCal.set(Calendar.MINUTE, 0);
		localCal.set(Calendar.SECOND, 0);
		localCal.set(Calendar.MILLISECOND, 0);
		return localCal;
	}
	private Calendar getEndOfDay(Calendar cal)	{
		Calendar localCal = (Calendar)cal.clone();
		localCal.set(Calendar.HOUR_OF_DAY, 23);
		localCal.set(Calendar.MINUTE, 59);
		localCal.set(Calendar.SECOND, 59);
		localCal.set(Calendar.MILLISECOND, 59);
		return localCal;
	}

	@SuppressWarnings("unchecked")
	public Double retrieveExerciseMax(Date startDate, Date endDate, String exercise)	{
		Double distance = 0.0;
		Double weight = 0.0;
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("");
		query.declareParameters("String nameParam");
		query.setFilter("timestamp > startDate && timestamp < endDate && eventType==nameParam");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate, String nameParam");
		query.setOrdering("timestamp desc");
		results = (List<TrackingEvent>) query.execute(startDate, endDate, exercise);
		
		for (TrackingEvent individual:results)	{
			Double currDistance = individual.getDistance();
			Double currWeight = individual.getWeight();
			
			if (currDistance>distance)
				distance = currDistance;
			if (currWeight>weight)	
				weight = currWeight;
		}
		if (exercise.equals("Cycling"))
			return distance;
		else if (exercise.equals("Running"))
			return distance;
		else if (exercise.equals("Swimming"))
			return distance;
		else 
			return weight;
	}
	
	public WeightEventDTO retrieveWeightEventDTO(Date startDate, Date endDate, String type)  {
        Double weightEventAmount = 0.0;
        List<WeightEvent> results; 
        List<WeightEventDTO> dtoResults = new ArrayList<WeightEventDTO>();
        Query query;
        query=pm.newQuery(WeightEvent.class);
        query.setFilter("");
        query.declareParameters("String typeParam");
        query.setFilter("timestamp > startDate && timestamp < endDate && weightEventType==typeParam");
        query.declareParameters("java.util.Date startDate, java.util.Date endDate, String typeParam");
        query.setOrdering("timestamp desc");
        results = (List<WeightEvent>) query.execute(startDate, endDate, type);
        
        for (WeightEvent individual:results)  {
            weightEventAmount = individual.getWeightEventScale();
            WeightEventDTO dto = individual.toDTO();
            return dto;     
        }
        return null;
	}
	
	@SuppressWarnings("unchecked")
	public TrackingEventDTO retrieveExerciseMaxDTO(Date startDate, Date endDate, String exercise)	{
		Double distance = 0.0;
		Double weight = 0.0;
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("");
		query.declareParameters("String nameParam");
		query.setFilter("timestamp > startDate && timestamp < endDate && eventType==nameParam");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate, String nameParam");
		query.setOrdering("timestamp desc");
		results = (List<TrackingEvent>) query.execute(startDate, endDate, exercise);
		
		for (TrackingEvent individual:results)	{
			Double currDistance = individual.getDistance();
			Double currWeight = individual.getWeight();
			
			if (currDistance>distance)
				distance = currDistance;
			if (currWeight>weight)	
				weight = currWeight;
		}
		TrackingEventDTO dto = new TrackingEventDTO();
		dto.setTimeStamp(startDate);
		dto.setDistance(distance);
		dto.setWeight(weight);
		return dto;
	}

/*	@SuppressWarnings("unchecked")
	public Double retrieveTotalSpend(Date startDate, Date endDate)	{
		List<Transaction> results; 
		Query query;
		query=pm.newQuery(Transaction.class);
		query.setFilter("timestamp > startDate && timestamp < endDate ");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate");
		query.setOrdering("timestamp desc");
		results = (List<Transaction>) query.execute(startDate, endDate);
		
		Double totalSpent = 0.0;
		Iterator<Transaction> iterator = results.iterator();
		while (iterator.hasNext())	{
			Transaction transaction = iterator.next();
			totalSpent += transaction.getAmount();
		}
		
		return totalSpent;
	}	*/
	
	@SuppressWarnings("unchecked")
	public Double retrieveWeightMax(String dataType, Date startDate, Date endDate)	{
		List<BodyStats> results; 
		Query query;
		query=pm.newQuery(BodyStats.class);
		query.setFilter("timestamp > startDate && timestamp < endDate ");
		query.declareParameters("java.util.Date startDate, java.util.Date endDate");
		query.setOrdering("timestamp desc");
		results = (List<BodyStats>) query.execute(startDate, endDate);
		
		Double maxValue = 0.0;
		Double currentValue = 0.0;
		for (BodyStats stat:results)	{
			if (dataType.equals("Weight"))
				currentValue = stat.getWeight();
			if (dataType.equals("Fat"))
				currentValue = stat.getFatPercentage() * stat.getWeight() / 100;
			if (dataType.equals("Water"))
				currentValue = stat.getWaterPercentage() * stat.getWeight() / 100;
			if (dataType.equals("Muscle"))
				currentValue = stat.getMusclePercentage() * stat.getWeight() / 100;
			if (dataType.equals("FatCalipers"))
				currentValue = stat.getFatCalipers().doubleValue();
			if (currentValue>maxValue)
				maxValue = currentValue;
		}
		return maxValue;
	}
	
	@SuppressWarnings("unchecked")
	public Boolean retrieveIllOrInjured()	{
		Boolean startEnd = false;
		
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType == eventType");
		query.declareParameters("String eventType");
		query.setOrdering("timestamp desc");
		results = (List<HealthEvent>) query.execute("Ill or Injury");
		
		if (results.size() > 0)	
			startEnd = ((HealthEvent)results.get(0)).getStartEnd().equals("Start");
		
		return startEnd;
	}
	
	public List<HealthEvent> retrieveHealthEvents(Date start, Date stop)	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("timestamp>=startParam && timestamp<=endParam");
		query.declareParameters("java.util.Date startParam, java.util.Date endParam");
		query.setOrdering("timestamp desc");
		results = (List<HealthEvent>) query.execute(start, stop);
		
		return results;
	}
	
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceExercise()	{
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("eventType==eventType1 || eventType==eventType2 || eventType==eventType3");
		query.setOrdering("timestamp desc");
		results = (List<TrackingEvent>) query.execute("Walking", "Running", "Swimming");
		
		Date lastExercise = null;
		if (results.size() > 0)	
			lastExercise = ((TrackingEvent)results.get(0)).getTimeStamp();
		
		Calendar now = Calendar.getInstance();
		Calendar lastExerciseCal = Calendar.getInstance();
		lastExerciseCal.setTime(lastExercise);
		Integer numberOfDays = daysBetween(lastExerciseCal, now);		
		return numberOfDays;
	}
	
	
	
	public HealthAlertDTO retrievePeriodSinceAlert(HealthAlertDTO dto)	{
		Integer numberOfPeriod = 0;
		if (dto.getEventType().equals("HealthEvent"))	{
			numberOfPeriod = retrievePeriodSinceHealthEvent(dto);
		} else if (dto.getEventType().equals("TrackingEvent"))	{
			numberOfPeriod = retrievePeriodSinceTrackingEvent(dto);
		} else if (dto.getEventType().equals("Transaction"))	{
			numberOfPeriod = retrievePeriodSinceTransactionEvent(dto);
		} else if (dto.getEventType().equals("ConsumptionEvent"))	{
			numberOfPeriod = retrievePeriodSinceConsumptionEvent(dto);
		}
		dto.setNumberOfPeriodsToDate(numberOfPeriod);
		return dto;
	}
	
	@SuppressWarnings("unchecked")
	public Integer retrievePeriodSinceHealthEvent(HealthAlertDTO dto)	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType==eventType");
		query.setOrdering("timestamp desc");
		query.declareParameters("String eventType");
		results = (List<HealthEvent>) query.execute(dto.getEventName());
		Integer number = 0;
		
		if (dto.getCount())	{
			Date startOfDay = DateUtility.getStartOfDay(new Date());
			for (HealthEvent result:results)	{
				if (result.getTimestamp().after(startOfDay))	{
					number++;
				}
			}
		} else {
			Date lastEvent = null;
			if (results.size() > 0)	
				lastEvent = ((HealthEvent)results.get(0)).getTimestamp();
			
			number = periodsBetween(dto, lastEvent);		
		}
		return number;
	}
	public Integer retrievePeriodSinceTrackingEvent(HealthAlertDTO dto)	{
		List<TrackingEvent> results; 
		Query query;
		if (dto.getEventName().equals("Cardio"))	{
			query=pm.newQuery(TrackingEvent.class);
			query.setFilter("eventType==eventTypeParam1 || eventType==eventTypeParam2 || eventType==eventTypeParam3 ");
			query.setOrdering("timestamp desc");
			query.declareParameters("String eventTypeParam1, String eventTypeParam2, String eventTypeParam3");
			results = (List<TrackingEvent>) query.execute("Running", "Cycling", "Walking");
		} else {
			query=pm.newQuery(TrackingEvent.class);
			query.setFilter("eventType==eventTypeParam");
			query.setOrdering("timestamp desc");
			query.declareParameters("String eventTypeParam");
			results = (List<TrackingEvent>) query.execute(dto.getEventName());
		}
		
		Date lastEvent = null;
		if (results.size() > 0)	
			lastEvent = ((TrackingEvent)results.get(0)).getTimeStamp();
		
		Integer numberOfDays = periodsBetween(dto, lastEvent);		
		return numberOfDays;
	}
	public Integer retrievePeriodSinceTransactionEvent(HealthAlertDTO dto)	{
		List<Transaction> results; 
		Query query;
		query=pm.newQuery(Transaction.class);
		query.setFilter("description==eventTypeParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("String eventTypeParam");
		results = (List<Transaction>) query.execute(dto.getEventName());
		
		Date lastEvent = null;
		if (results.size() > 0)	
			lastEvent = ((Transaction)results.get(0)).getTimestamp();
		
		Integer numberOfDays = periodsBetween(dto, lastEvent);		
		return numberOfDays;
	}
	
	public Integer retrievePeriodSinceConsumptionEvent(HealthAlertDTO dto)	{
		List<Consumption> results; 
		Query query;
		
		if (dto.getEventName().equals("Eaten"))	{
			query=pm.newQuery(Consumption.class);
			query.setFilter("calories > caloriesParam");
//			query.setOrdering("timestamp desc");
			query.declareParameters("Integer caloriesParam");
			Integer minimumCalories = 10;
			results = (List<Consumption>) query.execute(minimumCalories);
			// work around to avoid bug!!!!
			List<Consumption> revisedList = new ArrayList<Consumption>();
			for (Consumption consumption:results)	{
				if (consumption.getCalories() > 10)	{
					revisedList.add(consumption);
				}
			}
			results = revisedList;
		} else {
			query=pm.newQuery(Consumption.class);
			query.setFilter("meal==eventTypeParam");
//			query.setOrdering("timestamp desc");
			query.declareParameters("String eventTypeParam");
			results = (List<Consumption>) query.execute(dto.getEventName());
		}
		
		Collections.sort(results, new Comparator<Consumption>() {
            @Override
            public int compare(final Consumption object1, final Consumption object2) {
                return object2.getTimeStamp().compareTo(object1.getTimeStamp());
            }
           } );
		
		Date lastEvent = null;
		if (results.size() > 0)	
			lastEvent = ((Consumption)results.get(0)).getTimeStamp();
		
		Integer numberOfDays = periodsBetween(dto, lastEvent);		
		return numberOfDays;
	}
	private Integer periodsBetween(HealthAlertDTO dto, Date lastEvent)	{
		Calendar now = Calendar.getInstance();
		Calendar lastExerciseCal = Calendar.getInstance();
		lastExerciseCal.setTime(lastEvent!=null?lastEvent:new Date());
		Integer numberOfPeriods = 0;
		if (dto.getTimePeriod()!=null && dto.getTimePeriod().equals("Days"))	{
			numberOfPeriods = daysBetween(lastExerciseCal, now);		
		} else if (dto.getTimePeriod()!=null && dto.getTimePeriod().equals("Hours"))	{
			numberOfPeriods = hoursBetween(lastExerciseCal, now);		
		}
		return numberOfPeriods;
	}
	
	
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceSleep()	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType==eventType");
		query.setOrdering("timestamp desc");
		query.declareParameters("String eventType");
		results = (List<HealthEvent>) query.execute("Sleep Session");
		
		Date lastExercise = null;
		if (results.size() > 0)	
			lastExercise = ((HealthEvent)results.get(0)).getTimestamp();
		
		Calendar now = Calendar.getInstance();
		Calendar lastExerciseCal = Calendar.getInstance();
		lastExerciseCal.setTime(lastExercise);
		Integer numberOfDays = daysBetween(lastExerciseCal, now);		
		return numberOfDays;
	}
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceLowFrameOfMind()	{
		Integer daysSinceAnxious = retrieveDaysSinceFrameOfMind("Anxious");
		Integer daysSinceDepressed = retrieveDaysSinceFrameOfMind("Depressed");
		Integer daysSinceAnxiousAchieve = retrieveDaysSinceAchievements("Anxious");
		Integer daysSinceDepressedAchieve = retrieveDaysSinceAchievements("Depressed");
		Integer daysSinceLowWellBeing = checkDaysSinceHealthHealthEventTypeBelowScale("Well Being", 3);
		Integer daysSinceLowFrameOfMind = checkDaysSinceLowFrameOfMind();
		return Math.min(Math.min(Math.min(Math.min(Math.min(daysSinceAnxious, daysSinceDepressed), daysSinceLowWellBeing), daysSinceAnxiousAchieve), daysSinceDepressedAchieve), daysSinceLowFrameOfMind);
	}
	private Integer checkDaysSinceLowFrameOfMind()	{
		List<FrameOfMind> results; 
		Query query;
		query=pm.newQuery(FrameOfMind.class);
		query.setFilter("frameOfMindName==frameOfMindParamOne || frameOfMindName==frameOfMindParamTwo");
		query.setOrdering("timestamp desc");
		query.declareParameters("String frameOfMindParamOne, String frameOfMindParamTwo");
		results = (List<FrameOfMind>) query.execute("Depressed", "Anxious");
		
		Date lastExercise = null;
		if (results.size() > 0)	{
			lastExercise = ((FrameOfMind)results.get(0)).getTimestamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastExerciseCal = Calendar.getInstance();
			lastExerciseCal.setTime(lastExercise);
			Integer numberOfDays = daysBetween(lastExerciseCal, now);		
			return numberOfDays;
		}
		return 100;
	}
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceLowWellBeing()	{
		return checkDaysSinceHealthHealthEventTypeBelowScale("Well Being", 3);
	}
	
	public Integer getWellBeing()   {
	    Date dateFilter = DateUtility.addDays(new Date(), -2);
	    List<HealthEvent> results; 
        Query query;
        query=pm.newQuery(HealthEvent.class);
        query.setFilter("timestamp > startDateParam");
        query.declareParameters("java.util.Date startDateParam");
        query.setOrdering("timestamp desc");
        results = (List<HealthEvent>) query.execute(dateFilter);
        for (HealthEvent healthEvent:results)   {
            if (healthEvent.getHealthEventType().equals("Well Being"))    {
                return healthEvent.getHealthEventIntensityScale();
            }
        }
	    return 10;
	}
	
	private Integer checkDaysSinceHealthHealthEventTypeBelowScale(String eventType, Integer scale)	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType==eventType && healthEventIntensityScale <= eventIntensityScale");
//		query.setOrdering("timestamp desc");
		query.declareParameters("String eventType, Integer eventIntensityScale");
		results = (List<HealthEvent>) query.execute(eventType, scale);
	
		Collections.sort(results, new Comparator<HealthEvent>()	{
			public int compare(HealthEvent cons1, HealthEvent cons2)	{
				return cons2.getTimestamp().compareTo(cons1.getTimestamp());
			}
		});
		
		Date lastExercise = null;
		if (results.size() > 0)	{
			lastExercise = ((HealthEvent)results.get(0)).getTimestamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastExerciseCal = Calendar.getInstance();
			lastExerciseCal.setTime(lastExercise);
			Integer numberOfDays = daysBetween(lastExerciseCal, now);		
			return numberOfDays;
		}
		return 100;
	}
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceLowEnergy()	{
		return checkDaysSinceHealthHealthEventTypeBelowScale("Energy", 3);
	}
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceDump()	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType==eventType");
		query.setOrdering("timestamp desc");
		query.declareParameters("String eventType");
		results = (List<HealthEvent>) query.execute("Dump");
		
		Date lastExercise = null;
		for (HealthEvent event:results)	{
			if (event.getHealthEventIntensity().equals("Reasonable") || event.getHealthEventIntensity().equals("Significant"))	{
				lastExercise = event.getTimestamp();
				
				Calendar now = Calendar.getInstance();
				Calendar lastExerciseCal = Calendar.getInstance();
				lastExerciseCal.setTime(lastExercise);
				Integer numberOfDays = daysBetween(lastExerciseCal, now);		
				return numberOfDays;
			}
		}
		return null;
	}
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceStretch()	{
		List<TrackingEvent> results; 
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("eventType==sportType");
		query.declareParameters("String sportType");
		query.setOrdering("timestamp desc");
		results = (List<TrackingEvent>) query.execute("Stretching");
		
		Date lastExercise = null;
		if (results.size() > 0)		{
			lastExercise = ((TrackingEvent)results.get(0)).getTimeStamp();
		
			Calendar now = Calendar.getInstance();
			Calendar lastExerciseCal = Calendar.getInstance();
			lastExerciseCal.setTime(lastExercise);
			Integer numberOfDays = daysBetween(lastExerciseCal, now);		
			return numberOfDays;
		}
		return null;
	}
	
	public Integer retrieveHoursSinceBrushTeeth()	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType==eventType");
		query.setOrdering("timestamp desc");
		query.declareParameters("String eventType");
		results = (List<HealthEvent>) query.execute("Brush Teeth");
		
		Date lastBrushed = null;
		if (results.size() > 0)		{
			lastBrushed = ((HealthEvent)results.get(0)).getTimestamp();
		
			Calendar now = Calendar.getInstance();
			Calendar lastBrushedCal = Calendar.getInstance();
			lastBrushedCal.setTime(lastBrushed);
			
			Integer numberOfHours = hoursBetween(lastBrushedCal, now);		
			return numberOfHours;
		}
		return null;
	}

	public static Integer daysBetween(Calendar startDate, Calendar endDate) {  
		  Calendar date = (Calendar) startDate.clone();  
		  Calendar now = (Calendar) endDate.clone();
		  now.set(Calendar.HOUR_OF_DAY, 0);
		  now.set(Calendar.MINUTE, 0);
		  now.set(Calendar.SECOND, 0);
		  now.set(Calendar.MILLISECOND, 0);
		  
		  Integer daysBetween = 0;  
		  while (date.before(now)) {  
		    date.add(Calendar.DAY_OF_MONTH, 1);  
		    daysBetween++;  
		  }  
		  return daysBetween;  
	} 	
	
	public static Integer hoursBetween(Calendar startDate, Calendar endDate) {  
		  Calendar date = (Calendar) startDate.clone();  
		  Calendar now = (Calendar) endDate.clone();
		  
		  Integer hoursBetween = 0;  
		  date.add(Calendar.HOUR_OF_DAY, 1);  
		  while (date.before(now)) {  
		    date.add(Calendar.HOUR_OF_DAY, 1);  
		    hoursBetween++;  
		  }  
		  return hoursBetween;  
	} 		
	
	@SuppressWarnings("unchecked")
	public Integer retrieveTodaysHealtPoints()	{
		Calendar cal = Calendar.getInstance();
		return retrieveHealthPoints(cal);
	}
	/*
	public List<Double> getFinanceChartData(boolean weekly, int numberOfDataPoints)	{
		if (weekly)
			return getFinanceWeeklyData(numberOfDataPoints);
		else
			return getFinanceMonthlyData(numberOfDataPoints);
	}	*/
	/*
	public Double calculateAverageThisWeek()	{
		int weekOfYear = getWeekOfYear();
		Date startDate = getStartOfWeek(weekOfYear);
		Date endDate = getEndOfWeek(weekOfYear);
		Double number = retrieveTotalSpend(startDate, endDate);
		
		Calendar cal = Calendar.getInstance();
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		
		if (dayOfWeek == Calendar.SUNDAY)
			dayOfWeek=dayOfWeek+7;
		
		dayOfWeek = dayOfWeek-1;
		
		Double averageNumber = ((number / dayOfWeek)*7);
		return averageNumber;
	}	*/
	/*
	public List<Double> getFinanceWeeklyData(int numberOfDataPoints)	{
		List<Double> list = new ArrayList<Double>();
		Double number = 0.0;
		int weekOfYear = getWeekOfYear();
		for (int x=numberOfDataPoints-1; x>-1; x--)	{
			Date startDate = getStartOfWeek(weekOfYear-x);
			Date endDate = getEndOfWeek(weekOfYear-x);
			
			if (x==0)
				number = calculateAverageThisWeek();
			else
				number = retrieveTotalSpend(startDate, endDate);
			
			list.add(number);
		}
		return list;
	}	*/
	/*
	public List<Double> getFinanceMonthlyData(int numberOfDataPoints)	{
		List<Double> list = new ArrayList<Double>();
		Double number = 0.0;
		int monthOfYear = getMonthOfYear();
		for (int x=numberOfDataPoints-1; x>-1; x--)	{
			Date startDate = getStartOfMonth(monthOfYear-x);
			Date endDate = getEndOfMonth(monthOfYear-x);
			
			if (x==0)
				number = getAverageMonthlySpentThisMonth();
			else
				number = retrieveTotalSpend(startDate, endDate);
			list.add(number>100.0?(1700.0 - number):0);
		}
		return list;
	}	*/
	
	public List<Double> getExerciseChartData(String exercise, int numberOfDataPoints)	{
		List<Double> list = new ArrayList<Double>();
		Double number = 0.0;
		int year = getYear();
		int monthOfYear = getMonthOfYear();
		for (int x=numberOfDataPoints-1; x>-1; x--)	{
			Date startDate = getStartOfMonth(monthOfYear-x, year);
			Date endDate = getEndOfMonth(monthOfYear-x, year);
			
			number = retrieveExerciseMax(startDate, endDate, exercise);
			
			list.add(number);
		}
		return list;
	}
	
	public List<WeightEventDTO> getWeightEventChartDataDTO(String type, int numberOfDataPoints)    {
        List<WeightEventDTO> list = new ArrayList<WeightEventDTO>();
        WeightEventDTO dto = null;
        int weekOfYear = getWeekOfYear();
        for (int x=numberOfDataPoints-1; x>-1; x--) {
            Date startDate = getStartOfWeek(weekOfYear-x);
            Date endDate = getEndOfWeek(weekOfYear-x);
            
            dto = retrieveWeightEventDTO(startDate, endDate, type);
            if (dto!=null)  {
                list.add(dto);
            }
        }
        return list;
	}
	
	public List<TrackingEventDTO> getExerciseChartDataDTO(String exercise, int numberOfDataPoints)	{
		List<TrackingEventDTO> list = new ArrayList<TrackingEventDTO>();
		TrackingEventDTO dto = null;
		int weekOfYear = getWeekOfYear();
		for (int x=numberOfDataPoints-1; x>-1; x--)	{
			Date startDate = getStartOfWeek(weekOfYear-x);
			Date endDate = getEndOfWeek(weekOfYear-x);
			
			dto = retrieveExerciseMaxDTO(startDate, endDate, exercise);
			
			list.add(dto);
		}
		return list;
	}
	
		
	public List<Double> getWeightChartData(String exercise, Boolean monthlyOrWeekly, int numberOfDataPoints)	{
		if (monthlyOrWeekly)
			return getMonthlyWeightChartData(exercise, numberOfDataPoints);
		else
			return getWeeklyWeightChartData(exercise, numberOfDataPoints);
	}
	
	public List<Double> getMonthlyWeightChartData(String dataType, int numberOfDataPoints)	{
		List<Double> list = new ArrayList<Double>();
		Double number = 0.0;
		int year = getYear();
		int monthOfYear = getMonthOfYear();
		for (int x=numberOfDataPoints-1; x>-1; x--)	{
			Date startDate = getStartOfMonth(monthOfYear-x, year);
			Date endDate = getEndOfMonth(monthOfYear-x, year);
			
			number = retrieveWeightMax(dataType, startDate, endDate);
			
			list.add(number);
		}
		return list;
	}
	public List<Double> getWeeklyWeightChartData(String dataType, int  numberOfDataPoints)	{
		List<Double> list = new ArrayList<Double>();
		Double number = 0.0;
		int weekOfYear = getWeekOfYear();
		for (int x=numberOfDataPoints-1; x>-1; x--)	{
			Date startDate = getStartOfWeek(weekOfYear-x);
			Date endDate = getEndOfWeek(weekOfYear-x);
			
			number = retrieveWeightMax(dataType, startDate, endDate);
			
			list.add(number);
		}
		return list;		
	}
	
	
	public Integer getWeekOfYear()	{
		Calendar cal = Calendar.getInstance();
		return getWeekOfYear(cal);
	}
	public Integer getWeekOfYear(Calendar cal)	{
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		int weekOfYear = cal.get(Calendar.WEEK_OF_YEAR);
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		return weekOfYear;
	}
	
	public Date getStartOfWeek(int weekNumber)	{
		Calendar cal = Calendar.getInstance();
		int year = cal.get(Calendar.YEAR);
		cal.clear();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		cal.set(Calendar.WEEK_OF_YEAR, weekNumber);
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		return cal.getTime();
	}

	public Date getEndOfWeek(int weekNumber)	{
		Calendar cal = Calendar.getInstance();
		int year = cal.get(Calendar.YEAR);
		cal.clear();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		cal.set(Calendar.WEEK_OF_YEAR, weekNumber);
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		return cal.getTime();
	}
		
	public int getMonthOfYear()	{
		Calendar cal = Calendar.getInstance();
		return cal.get(Calendar.MONTH);
	}
	public int getYear()	{
		Calendar cal = Calendar.getInstance();
		return cal.get(Calendar.YEAR);
	}
	public Date getStartOfMonth(int monthNumber, int year)	{
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, monthNumber);
		cal.set(Calendar.DATE, 1);		
		cal.getTime();
		
		int day = cal.get(Calendar.DAY_OF_WEEK);
		
		if ((day!=Calendar.MONDAY)&&(day!=Calendar.TUESDAY)&&(day!=Calendar.WEDNESDAY))	{
			cal.add(Calendar.WEEK_OF_MONTH, 1);
		}

		cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		cal.set(Calendar.MILLISECOND, 0);
	
		return cal.getTime();
	}

	public Date getEndOfMonth(int monthNumber, int year)	{
		Date startDate = getStartOfMonth(monthNumber, year);

		Calendar cal = Calendar.getInstance();
		cal.setTime(startDate);
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		
		cal.add(Calendar.WEEK_OF_YEAR, 4);
		cal.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
		cal.getTime();
		
		int dateOfMonth = cal.get(Calendar.DATE);
		
		if (dateOfMonth < 20)	{
			cal.add(Calendar.WEEK_OF_YEAR, -1);
			cal.getTime();
		}
		cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
		cal.set(Calendar.HOUR_OF_DAY, 23);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		return cal.getTime();
	}
	
	public int getNumberOfWeeksInMonth()	{
		int numberOfWeeksInMonth = 5;
		
		Calendar startCal = Calendar.getInstance();
		Date startDate = getStartOfMonth(startCal.get(Calendar.MONTH), startCal.get(Calendar.YEAR));

		Calendar cal = Calendar.getInstance();
		cal.setTime(startDate);
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		
		cal.add(Calendar.WEEK_OF_YEAR, (numberOfWeeksInMonth-1));
		cal.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
		cal.getTime();
		
		int dateOfMonth = cal.get(Calendar.DATE);
		
		if (dateOfMonth < 20)	
			numberOfWeeksInMonth--;
		return numberOfWeeksInMonth;
	}
	
	public int getNumberOfWeeksLastMonth()	{
		int numberOfWeeksInMonth = 5;
		
		Calendar startCal = Calendar.getInstance();
		startCal.add(Calendar.MONTH, -1);
		startCal.getTime();
		Date startDate = getStartOfMonth(startCal.get(Calendar.MONTH), startCal.get(Calendar.YEAR));

		Calendar cal = Calendar.getInstance();
		cal.setTime(startDate);
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(5);
		
		cal.add(Calendar.WEEK_OF_YEAR, (numberOfWeeksInMonth-1));
		cal.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
		cal.getTime();
		
		int dateOfMonth = cal.get(Calendar.DATE);
		
		if (dateOfMonth < 20)	
			numberOfWeeksInMonth--;
		return numberOfWeeksInMonth;
	}
	
	
	@SuppressWarnings("unchecked")
	public Integer retrieveHealthPoints(Calendar calToday)	{
		Integer points = 0;
		Date start = getStartOfDay(calToday).getTime();
		Date end = getEndOfDay(calToday).getTime();
		
		List<HealthEvent> results; 
		Query query;

		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		List<Object> parameters = new ArrayList<Object>();
		parameters.add("Sleep Session");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*10;

		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Brush Teeth");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*10;

		results = null;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("(eventType == event1 || eventType == event2 || eventType == event3|| eventType == event4 || eventType == event5) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String event1, String event2, String event3, String event4, String event5, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Stretching");
		parameters.add("Walking");
		parameters.add("Cycling");
		parameters.add("Running");
		parameters.add("Swimming");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*10);
		
		query=pm.newQuery(Consumption.class);
		query.setFilter("(meal == eventType1 || meal == eventType2 || meal == eventType3 || meal == eventType4 || meal == eventType5) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType1, String eventType2, String eventType3, String eventType4, String eventType5, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Veg");
		parameters.add("Fruit");
		parameters.add("Muesli");
		parameters.add("Water");
		parameters.add("Salad");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*10;	
		
		return points;
	}
	
	/*
	@SuppressWarnings("unchecked")
	public Integer retrieveHealthPoints(Calendar calToday)	{
		Integer points;
		Date start = getStartOfDay(calToday).getTime();
		Date end = getEndOfDay(calToday).getTime();
		
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		List parameters = new ArrayList<Object>();
		parameters.add("Achieve");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = results.size()*6;

		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Achieve");
		parameters.add("Reasonable");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*4);
		
		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Achieve");
		parameters.add("Insignificant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);

		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Positive Event");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*3;

		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Positive Event");
		parameters.add("Reasonable");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);
		
		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Positive Event");
		parameters.add("Insignificant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*1);
		
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Dump");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*6;

		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Dump");
		parameters.add("Reasonable");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*4);
		
		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Dump");
		parameters.add("Insignificant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);

		
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Sleep Session");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*6;

		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Sleep Session");
		parameters.add("Reasonable");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*4);
		
		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Sleep Session");
		parameters.add("Insignificant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);

		
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Brain Fed");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*6;

		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Brain Fed");
		parameters.add("Reasonable");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*4);
		
		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Brain Fed");
		parameters.add("Insignificant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);
		
		
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Social");
		parameters.add("Significant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + results.size()*6;

		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Social");
		parameters.add("Reasonable");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*4);
		
		results = null;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("(healthEventType == eventType && healthEventIntensity==intensity) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String eventType, String intensity, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Social");
		parameters.add("Insignificant");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);
				
		
		
		results = null;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("(eventType == event1 || eventType == event2 || eventType == event3|| eventType == event4 || eventType == event5) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String event1, String event2, String event3, String event4, String event5, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Stretching");
		parameters.add("Walking");
		parameters.add("Cycling");
		parameters.add("Running");
		parameters.add("Swimming");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*6);
		
		results = null;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("(eventType == event1 || eventType == event2 || eventType == event3|| eventType == event4 || eventType == event5 || eventType == event6 ) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String event1, String event2, String event3, String event4, String event5, String event6, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Leg Extension");
		parameters.add("Leg Curls");
		parameters.add("Squats");
		parameters.add("Abs");
		parameters.add("Butterfly Press");
		parameters.add("Vertical Press");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()*2);
		
		results = null;
		query=pm.newQuery(Transaction.class);
		query.setFilter("(transactionType == event ) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String event, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Date");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()>0?10:0);

		results = null;
		query=pm.newQuery(Transaction.class);
		query.setFilter("(transactionType == event ) && timestamp > startDate && timestamp < endDate ");
		query.declareParameters("String event, java.util.Date startDate, java.util.Date endDate");
		parameters = new ArrayList<Object>();
		parameters.add("Weekly Shop");
		parameters.add(start);
		parameters.add(end);
		
		results = (List<HealthEvent>) query.executeWithArray(parameters.toArray());
		points = points + (results.size()>0?6:0);
		
		return points;
	}	*/


	public Boolean insertHealthEvent(HealthEvent healthEvent)	{
		Boolean success = true;
		try	{
			pm.makePersistent(healthEvent);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	public Boolean insertWeightEvent(WeightEvent weightEvent)	{
		Boolean success = true;
		try	{
			pm.makePersistent(weightEvent);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	public Boolean insertBodyEvent(BodyStats bodyStats)	{
		Boolean success = true;
		try	{
			pm.makePersistent(bodyStats);
		} 
		catch (Exception e)	{
			success = false;
		}
		return success;
	}
	public Integer retrieveHoursSinceWater()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		Date lastWater = null;
		if (results.size() > 0)		{
			for (Consumption consumption:results)	{
				if (consumption.getWater() > 0.0)	{
					lastWater = consumption.getTimeStamp();
					
					Calendar now = Calendar.getInstance();
					Calendar lastWaterCal = Calendar.getInstance();
					lastWaterCal.setTime(lastWater);
					
					Integer numberOfHours = hoursBetween(lastWaterCal, now);		
					return numberOfHours;
				}
			}
		}
		return null;
	}
	
	public Integer retrieveDaysSinceSalad()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		query.setFilter("meal == mealParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("String mealParam");
		results = (List<Consumption>) query.execute("Salad");
		
		Date lastFood = null;
		if (results.size() > 0)		{
			Consumption consumption = results.get(0);
			lastFood = consumption.getTimeStamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastFoodCal = Calendar.getInstance();
			lastFoodCal.setTime(lastFood);
			
			Integer numberOfHours = daysBetween(lastFoodCal, now);		
			return numberOfHours;
		}
		return null;
	}
	public Integer retrieveDaysSinceFruit()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		query.setFilter("meal == mealParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("String mealParam");
		results = (List<Consumption>) query.execute("Fruit");
		
		Date lastFood = null;
		if (results.size() > 0)		{
			Consumption consumption = results.get(0);
			lastFood = consumption.getTimeStamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastFoodCal = Calendar.getInstance();
			lastFoodCal.setTime(lastFood);
			
			Integer numberOfHours = daysBetween(lastFoodCal, now);		
			return numberOfHours;
		}
		return null;
	}
	public Integer retrieveDaysSinceVeg()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		query.setFilter("meal == mealParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("String mealParam");
		results = (List<Consumption>) query.execute("Veg");
		
		Date lastFood = null;
		if (results.size() > 0)		{
			Consumption consumption = results.get(0);
			lastFood = consumption.getTimeStamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastFoodCal = Calendar.getInstance();
			lastFoodCal.setTime(lastFood);
			
			Integer numberOfHours = daysBetween(lastFoodCal, now);		
			return numberOfHours;
		}
		return null;
	}	
	public Integer retrieveDaysSinceRoughage()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		query.setFilter("meal == mealParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("String mealParam");
		results = (List<Consumption>) query.execute("Muesli");
		
		Date lastFood = null;
		if (results.size() > 0)		{
			Consumption consumption = results.get(0);
			lastFood = consumption.getTimeStamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastFoodCal = Calendar.getInstance();
			lastFoodCal.setTime(lastFood);
			
			Integer numberOfHours = daysBetween(lastFoodCal, now);		
			return numberOfHours;
		}
		return null;
	}	
	
	public Integer retrieveHoursSinceFood()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		Date lastFood = null;
		if (results.size() > 0)		{
			for (Consumption consumption:results)	{
				if (consumption.getCalories() > 0.0)	{
					lastFood = consumption.getTimeStamp();
					
					Calendar now = Calendar.getInstance();
					Calendar lastFoodCal = Calendar.getInstance();
					lastFoodCal.setTime(lastFood);
					
					Integer numberOfHours = hoursBetween(lastFoodCal, now);		
					return numberOfHours;
				}
			}
		}
		return null;
	}
	public String retrieveFirstEaten()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp asc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		Date firstFood = null;
		if (results.size() > 0)		{
			for (Consumption consumption:results)	{
				if (consumption.getCalories() > 0.0)	{
					firstFood = consumption.getTimeStamp();
					
					Calendar firstFoodCal = Calendar.getInstance();
					firstFoodCal.setTime(firstFood);
					
					Integer hour = firstFoodCal.get(Calendar.HOUR_OF_DAY);
					Integer minute = firstFoodCal.get(Calendar.MINUTE);
					return hour.toString() + ":" + minute;
				}
			}
		}
		return "";
	}
	public Integer retrieveHoursSinceEaten()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp > timestampParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date timestampParam");
		results = (List<Consumption>) query.execute(DateUtility.getStartOfDay(new Date()));
		
		Date lastFood = null;
		if (results.size() > 0)		{
			for (Consumption consumption:results)	{
				if (consumption.getCalories() > 0.0)	{
					lastFood = consumption.getTimeStamp();
					
					Calendar now = Calendar.getInstance();
					Calendar lastFoodCal = Calendar.getInstance();
					lastFoodCal.setTime(lastFood);
					
					Integer numberOfHours = hoursBetween(lastFoodCal, now);		
					return numberOfHours;
				}
			}
		}
		return null;
	}	

	public Integer retrieveDaysSinceBisacodyl()	{
		List<Consumption> results; 
		Query query;
		query=pm.newQuery(Consumption.class);
		query.setFilter("meal == mealParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("String mealParam");
		results = (List<Consumption>) query.execute("Bisacodyl");

//		Collections.sort(results, new Comparator<Consumption>()	{
//			public int compare(Consumption cons1, Consumption cons2)	{
//				return cons1.getTimeStamp().compareTo(cons2.getTimeStamp());
//			}
//		});
		
		
		Date lastFood = null;
		if (results.size() > 0)		{
//			for (Consumption consumption:results)	{
				Consumption consumption = results.get(0);
				lastFood = consumption.getTimeStamp();
				
				Calendar now = Calendar.getInstance();
				Calendar lastFoodCal = Calendar.getInstance();
				lastFoodCal.setTime(lastFood);
				
				Integer numberOfHours = daysBetween(lastFoodCal, now);		
				return numberOfHours;
//			}
		}
		return null;
	}
	
	public Integer retrieveDaysSinceBloated()	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType==eventType && (healthEventIntensityScale >= intensityOne)");
//		query.setOrdering("timestamp desc");
		query.declareParameters("String eventType, Integer intensityOne");
		results = (List<HealthEvent>) query.execute("Bloated", 5);

		Collections.sort(results, new Comparator<HealthEvent>()	{
			public int compare(HealthEvent cons1, HealthEvent cons2)	{
				return cons2.getTimestamp().compareTo(cons1.getTimestamp());
			}
		});
		
		
		Date lastFood = null;
		if (results.size() > 0)		{
//			for (HealthEvent consumption:results)	{
				HealthEvent consumption = results.get(0);
				lastFood = consumption.getTimestamp();
				
				Calendar now = Calendar.getInstance();
				Calendar lastFoodCal = Calendar.getInstance();
				lastFoodCal.setTime(lastFood);
				
				Integer numberOfHours = daysBetween(lastFoodCal, now);		
				return numberOfHours;
	//		}
		}
		return null;
	}	
	public Integer retrieveNumberOfBrushesToday()	{
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("timestamp > dateParam && healthEventType==eventType");
//		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date dateParam, String eventType");
		results = (List<HealthEvent>) query.execute(DateUtility.getStartOfDay(new Date()), "Brush Teeth");

		return results.size();
	}
	
	public List<String> retrieveAchievements() {
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("timestamp > startParam && timestamp < endParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date startParam, java.util.Date endParam");
		results = (List<HealthEvent>) query.execute(DateUtility.getStartOfWeek(new Date()), new Date());

        Collections.sort(results, new Comparator<HealthEvent>() {
            @Override
            public int compare(HealthEvent arg0, HealthEvent arg1) {
                Integer d1 = arg0.getHealthEventIntensityScale();
                Integer d2 = arg1.getHealthEventIntensityScale();
                if (d1==null || d2==null)   {
                    return 0;
                } else {
                    return (d1 > d2 ? -1 : 1);     //descending
                }
            }
        });
		
		
		List<String> achievements = new ArrayList<String>();
		for (HealthEvent event:results)	{
			achievements.add(event.getDescription());
		}

		return achievements;
	}
	public List<String> retrieveAchievements(String frameOfMind, Integer weekNumber) {
		Date date = DateUtility.addWeeks(new Date(), -weekNumber);
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("timestamp > startParam && timestamp < endParam && healthEventFrameOfMind == frameOfMindParam");
		query.setOrdering("timestamp desc");
		query.declareParameters("java.util.Date startParam, java.util.Date endParam, String frameOfMindParam");
		results = (List<HealthEvent>) query.execute(DateUtility.getStartOfWeek(date), DateUtility.getEndOfWeek(date), frameOfMind);
		List<String> achievements = new ArrayList<String>();
        Collections.sort(results, new Comparator<HealthEvent>() {
            @Override
            public int compare(HealthEvent arg0, HealthEvent arg1) {
                Integer d1 = arg0.getHealthEventIntensityScale();
                Integer d2 = arg1.getHealthEventIntensityScale();
                if (d1==null || d2==null)   {
                    return 0;
                } else {
                    return (d1 > d2 ? -1 : 1);     //descending
                }
            }
        });
		for (HealthEvent event:results)	{
			achievements.add(event.getDescription());
		}
		return achievements;
	}
    public List<String> retrieveAchievements(Date startDate, Date endDate, String intensity, String frameOfMind) throws IllegalArgumentException   {
        List<HealthEvent> results; 
        Query query;
        query=pm.newQuery(HealthEvent.class);
        query.setFilter("timestamp > startParam && timestamp < endParam && healthEventType == healthEventTypeParam");
        query.setOrdering("timestamp desc");
        query.declareParameters("java.util.Date startParam, java.util.Date endParam, String healthEventTypeParam");
        results = (List<HealthEvent>) query.execute(startDate, endDate, "Achieve");
        List<String> achievements = new ArrayList<String>();
        Collections.sort(results, new Comparator<HealthEvent>() {
            @Override
            public int compare(HealthEvent arg0, HealthEvent arg1) {
                Integer d1 = arg0.getHealthEventIntensityScale();
                Integer d2 = arg1.getHealthEventIntensityScale();
                if (d1==null || d2==null)   {
                    return 0;
                } else {
                    return (d1 > d2 ? -1 : 1);     //descending
                }
            }
        });
        for (HealthEvent event:results) {
            String frameOfMindString = event.getHealthEventFrameOfMind()!=null?event.getHealthEventFrameOfMind():"";
            Integer intensityInt = event.getHealthEventIntensityScale()!=null?event.getHealthEventIntensityScale():0;
            String timestamp = event.getTimestamp()!=null?event.getTimestamp().toString():"";
            String text = event.getDescription() 
                + "          ( " 
                + intensityInt.toString() 
                + " )";
            boolean intBool = false;
            if ((intensity.length() <= 0) || (intensity.length() > 0 && intensityInt >= Integer.parseInt(intensity))) {
                intBool = true;
            }
            boolean fomBool = false;
            if ((frameOfMind.length() <= 0) || (frameOfMind.length() > 0 && frameOfMind.equals(frameOfMindString)))   {
                fomBool = true;
            }
            if (intBool && fomBool) {
                achievements.add(text);
            }
        }
        return achievements;
    }
	
	public Integer retrieveDaysSinceAchievements(String frameOfMind) {
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventFrameOfMind == frameOfMindParam");
//		query.setOrdering("timestamp desc");
		query.declareParameters("String frameOfMindParam");
		results = (List<HealthEvent>) query.execute(frameOfMind);
		
		Collections.sort(results, new Comparator<HealthEvent>()	{
			public int compare(HealthEvent cons1, HealthEvent cons2)	{
				return cons2.getTimestamp().compareTo(cons1.getTimestamp());
			}
		});
		
		Date lastExercise = null;
		if (results.size() > 0)	{
			lastExercise = ((HealthEvent)results.get(0)).getTimestamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastExerciseCal = Calendar.getInstance();
			lastExerciseCal.setTime(lastExercise);
			Integer numberOfDays = daysBetween(lastExerciseCal, now);		
			return numberOfDays;
		}
		return 100;
	}
	@SuppressWarnings("unchecked")
	public Integer retrieveDaysSinceFrameOfMind(String frameOfMind)	{
		Integer daysSinceFrameOfMindAchieve = 100;
		daysSinceFrameOfMindAchieve = retrieveDaysSinceAchievements(frameOfMind);
		List<FrameOfMind> results; 
		Query query;
		query=pm.newQuery(FrameOfMind.class);
		query.setFilter("frameOfMindName==frameOfMindParamOne");
//		query.setOrdering("timestamp desc");
		query.declareParameters("String frameOfMindParamOne");
		results = (List<FrameOfMind>) query.execute(frameOfMind);
		
		Collections.sort(results, new Comparator<FrameOfMind>()	{
			public int compare(FrameOfMind cons1, FrameOfMind cons2)	{
				return cons2.getTimestamp().compareTo(cons1.getTimestamp());
			}
		});

		Date lastExercise = null;
		if (results.size() > 0)	{
			lastExercise = ((FrameOfMind)results.get(0)).getTimestamp();
			
			Calendar now = Calendar.getInstance();
			Calendar lastExerciseCal = Calendar.getInstance();
			lastExerciseCal.setTime(lastExercise);
			Integer numberOfDays = daysBetween(lastExerciseCal, now);	
			if (numberOfDays < daysSinceFrameOfMindAchieve)	{
				daysSinceFrameOfMindAchieve = numberOfDays;
			}
		}
		return daysSinceFrameOfMindAchieve;
	}
	public List<HealthAlertDTO> retrieveHealthAlerts()	{
		List<HealthAlertDTO> dtoResults = new ArrayList<HealthAlertDTO>(); 
		List<HealthAlert> results; 
		Query query;
		query=pm.newQuery(HealthAlert.class);
//		query.setOrdering("tab, column, row");
		results = (List<HealthAlert>) query.execute();
		
		try	{
			Collections.sort(results, new Comparator<HealthAlert>()	{
				public int compare(HealthAlert cons1, HealthAlert cons2)	{
					int c;
					c = compareObjects(cons1.getTab(), cons2.getTab());
					if (c==0)
						c = compareObjects(cons1.getColumn(), cons2.getColumn());
					if (c==0)
						c = compareObjects(cons1.getRow(), cons2.getRow());
					if (c==0)
						c = compareObjects(cons1.getEventType(), cons2.getEventType());
					if (c==0)
						c = compareObjects(cons1.getEventName(), cons2.getEventName());
					
					return c;
				}
			});
		} catch (Exception e)	{
			
		}
		
		for (HealthAlert healthAlert:results)	{
			dtoResults.add(healthAlert.toDTO());
		}
		return dtoResults;
	}
	public List<HealthAlertDTO> retrieveHealthAlerts(String tabTitle)	{
		List<HealthAlertDTO> dtoResults = new ArrayList<HealthAlertDTO>(); 
		List<HealthAlert> results; 
		Query query;
		query=pm.newQuery(HealthAlert.class);
		query.setFilter("tab==tabParam");
		query.declareParameters("String tabParam");
//		query.setOrdering("tab, column, row");
		results = (List<HealthAlert>) query.execute(tabTitle);
		
		try	{
			Collections.sort(results, new Comparator<HealthAlert>()	{
				public int compare(HealthAlert cons1, HealthAlert cons2)	{
					int c;
					c = compareObjects(cons1.getTab(), cons2.getTab());
					if (c==0)
						c = compareObjects(cons1.getRow(), cons2.getRow());
					if (c==0)
						c = compareObjects(cons1.getColumn(), cons2.getColumn());
					if (c==0)
						c = compareObjects(cons1.getEventType(), cons2.getEventType());
					if (c==0)
						c = compareObjects(cons1.getEventName(), cons2.getEventName());
					
					return c;
				}
			});
		} catch (Exception e)	{
			
		}
		
		for (HealthAlert healthAlert:results)	{
			dtoResults.add(healthAlert.toDTO());
		}
		return dtoResults;
	}
	private int compareObjects(String cons1, String cons2)	{
		String comp1 = cons1!=null?cons1:"";
		String comp2 = cons2!=null?cons2:"";
		return comp1.compareTo(comp2);
	}
	private int compareObjects(Integer cons1, Integer cons2)	{
		Integer comp1 = cons1!=null?cons1:10000;
		Integer comp2 = cons2!=null?cons2:10000;
		return comp1.compareTo(comp2);
	}
	
	public String updateHealthAlert(HealthAlertDTO dto)
			throws IllegalArgumentException {
		HealthAlert healthAlert;
		if (dto.getId()!=null)	{
			healthAlert = pm.getObjectById(HealthAlert.class, dto.getId());
			healthAlert.update(dto);
		}
		else	{ 
			healthAlert = new HealthAlert(dto);
		}
		pm.makePersistent(healthAlert);
		return healthAlert.getId().toString();
	}
	private boolean todaysDate(Date date)	{
		Calendar cal = Calendar.getInstance();
		Calendar dateCal = Calendar.getInstance();
		dateCal.setTime(date);
		return calendarsEqual(cal, dateCal);
	}
	private boolean calendarsEqual(Calendar calOne, Calendar calTwo)	{
		int yearOne = calOne.get(Calendar.YEAR);
		int yearTwo = calTwo.get(Calendar.YEAR);
		int monthOne = calOne.get(Calendar.MONTH);
		int monthTwo = calTwo.get(Calendar.MONTH);
		int dayOne = calOne.get(Calendar.DAY_OF_MONTH);
		int dayTwo = calTwo.get(Calendar.DAY_OF_MONTH);
		if (yearOne==yearTwo)	{
			if (monthOne == monthTwo) {
				if (dayOne == dayTwo)	{
					return true;
				}
			}
		}
		return false;
	}
	private Integer getHour(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		return cal.get(Calendar.HOUR_OF_DAY);
	}
	private Integer getYear(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		return cal.get(Calendar.YEAR);
	}
	private Integer getMonth(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		return cal.get(Calendar.MONTH);
	}
	private Integer getWeek(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		return cal.get(Calendar.WEEK_OF_YEAR);
	}	
	private Integer getDayOfYear(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		return cal.get(Calendar.DAY_OF_YEAR);
	}	
	private Integer getDayOfWeek(Date now)	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(now);
		return cal.get(Calendar.DAY_OF_WEEK);
	}	
	public List<TimeTableTaskDTO> retrieveTimeTableTasks(Date now)	throws IllegalArgumentException {
		Date startDate = DateUtility.getStartOfDay(now);
		Date endDate = DateUtility.getEndOfDay(now);
		int hour = todaysDate(now)?getHour(now):0;
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("date>=startDateParam && date <=endDateParam");
//		query.setOrdering("hour");
		query.declareParameters("java.util.Date startDateParam, java.util.Date endDateParam");
		results = (List<TimeTableTask>) query.execute(startDate, endDate);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				return compareObjects(cons1.getHour(), cons2.getHour());
			}
		});
				
		
		for (TimeTableTask timeTableTask:results)	{
			if (timeTableTask.getHour()!=null && timeTableTask.getHour() >= hour && timeTableTask.getHour() <= 23)
				dtoResults.add(timeTableTask.toDTO());
		}
		return dtoResults;
	}
	
	public List<TimeTableTaskDTO> retrieveTimeTableTasks(Boolean yearly, Boolean monthly, Boolean weekly, Boolean daily, Boolean holidays, Date now)	throws IllegalArgumentException {
		if (yearly)	{
			return retrieveYearlyTimeTableTask(now);
		}	else if (monthly)	{
			return retrieveMonthlyTimeTableTask(now);
		}	else if (weekly)	{
			return retrieveWeeklyTimeTableTask(now);
		}	else if (daily)		{
			return retrieveDailyTimeTableTask(now);
		}	else if (holidays)		{
			return retrieveHolidays(now);
		}
		return null;
	}

	public List<TimeTableTaskDTO> retrieveTimeTableFuel(Boolean yearly, Boolean monthly, Boolean weekly, Boolean daily, Boolean holidays, Date now)	throws IllegalArgumentException {
		if (daily)		{
			return retrieveDailyTimeTableFuel(now);
		}	
		return null;
	}
	
	private List<TimeTableTaskDTO> retrieveYearlyTimeTableTask(Date now)	{
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
		int year = todaysDate(now)?getYear(now):0;
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("year >= yearParam");
		query.declareParameters("Integer yearParam");
		results = (List<TimeTableTask>) query.execute(year);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				return cons1.getYear().compareTo(cons2.getYear());
			}
		});
		
		for (TimeTableTask timeTableTask:results)	{
			if (timeTableTask.getYear() !=null)
				dtoResults.add(timeTableTask.toDTO());
		}
		return dtoResults;
	}
	
	private List<TimeTableTaskDTO> retrieveMonthlyTimeTableTask(Date now)	{
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
        int month = todaysDate(now)?getMonth(now):0;
        int year = getYear(now);
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("month >= monthParam && monthYear == monthYearParam");
		query.declareParameters("Integer monthParam, Integer monthYearParam");
		results = (List<TimeTableTask>) query.execute(month, year);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				return cons1.getMonth().compareTo(cons2.getMonth());
			}
		});
		
		for (TimeTableTask timeTableTask:results)	{
			if (timeTableTask.getMonth()!=null)
				dtoResults.add(timeTableTask.toDTO());
		}
		return dtoResults;
	}
		
	private List<TimeTableTaskDTO> retrieveHolidays(Date now)	{
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
		int week = todaysDate(now)?getWeek(now):0;
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("holidayUnit >= holidayUnitParam");
		query.declareParameters("Integer holidayUnitParam");
		results = (List<TimeTableTask>) query.execute(0);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				return cons1.getHolidayUnit().compareTo(cons2.getHolidayUnit());
			}
		});
		int count = 1;
		for (TimeTableTask timeTableTask:results)	{
			if ((timeTableTask.getHolidayUnit() !=null) && (timeTableTask.getHolidayUnit() < count))	{
				int maxNumber = timeTableTask.getHolidayUnit();
				while (count < maxNumber)	{
					TimeTableTaskDTO newDTO = new TimeTableTaskDTO();
					newDTO.setHolidayUnit(count++);
					dtoResults.add(newDTO);
				}
			}
			if (timeTableTask.getHolidayUnit() !=null )	{
				dtoResults.add(timeTableTask.toDTO());
			}
			count++;
		}
		while (count < 21)	{
			TimeTableTaskDTO newDTO = new TimeTableTaskDTO();
			newDTO.setHolidayUnit(count++);
			dtoResults.add(newDTO);
		}
		Collections.sort(dtoResults, new Comparator<TimeTableTaskDTO>()	{
			public int compare(TimeTableTaskDTO cons1, TimeTableTaskDTO cons2)	{
				return cons2.getHolidayUnit().compareTo(cons1.getHolidayUnit());
			}
		});
		
		return dtoResults;
	}
	private List<TimeTableTaskDTO> retrieveWeeklyTimeTableTask(Date now)	{
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
		int week = todaysDate(now)?getWeek(now):0;
        int year = getYear(now);
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("week >= weekParam && weekYear == weekYearParam");
		query.declareParameters("Integer weekParam, Integer weekYearParam");
		results = (List<TimeTableTask>) query.execute(week, year);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				return cons1.getWeek().compareTo(cons2.getWeek());
			}
		});
		
		for (TimeTableTask timeTableTask:results)	{
			if (timeTableTask.getWeek() !=null )
				dtoResults.add(timeTableTask.toDTO());
		}
		return dtoResults;
	}
	
	private int getNumberOfDays(int dayOfWeek)	{
//		if (dayOfWeek==1)	{
//			return 1;
//		} else if (dayOfWeek < 6)	{
//			return 3;
//		} else if (dayOfWeek == 7)	{
//			return 2;
//		}
		return 4;
	}
		
	private List<TimeTableTaskDTO> retrieveDailyTimeTableTask(Date now)	{
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
		int day = getDayOfYear(now);
		int dayOfWeek = getDayOfWeek(now);
		int numberOfDays = getNumberOfDays(dayOfWeek);
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("dayOfYear >= dayParam && dayOfYear <= dayTwoParam");
		query.declareParameters("Integer dayParam, Integer dayTwoParam");
		results = (List<TimeTableTask>) query.execute(day, day+numberOfDays-1);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				int c = cons1.getDayFraction().compareTo(cons2.getDayFraction());
				if (c==0)	{
					c = cons1.getDayOfYear().compareTo(cons2.getDayOfYear());
				}
				return c;
			}
		});
		
		for (TimeTableTask timeTableTask:results)	{
			if (timeTableTask.getDayFraction() !=null && timeTableTask.getDayOfYear() !=null && timeTableTask.getTask()!=null)
				dtoResults.add(timeTableTask.toDTO());
		}
		return dtoResults;
	}
	
	private List<TimeTableTaskDTO> retrieveDailyTimeTableFuel(Date now)	{
		List<TimeTableTaskDTO> dtoResults = new ArrayList<TimeTableTaskDTO>(); 
		List<TimeTableTask> results; 
		int day = getDayOfYear(now);
		int dayOfWeek = getDayOfWeek(now);
		int numberOfDays = getNumberOfDays(dayOfWeek);
		Query query;
		query=pm.newQuery(TimeTableTask.class);
		query.setFilter("dayOfYear >= dayParam && dayOfYear <= dayTwoParam");
		query.declareParameters("Integer dayParam, Integer dayTwoParam");
		results = (List<TimeTableTask>) query.execute(day, day+numberOfDays-1);
		
		Collections.sort(results, new Comparator<TimeTableTask>()	{
			public int compare(TimeTableTask cons1, TimeTableTask cons2)	{
				int c = cons1.getDayFraction().compareTo(cons2.getDayFraction());
				if (c==0)	{
					c = cons1.getDayOfYear().compareTo(cons2.getDayOfYear());
				}
				return c;
			}
		});
		
		for (TimeTableTask timeTableTask:results)	{
			if (timeTableTask.getDayFraction() !=null && timeTableTask.getDayOfYear() !=null && timeTableTask.getFuel()!=null)
				dtoResults.add(timeTableTask.toDTO());
		}
		return dtoResults;
	}	
	
	public String updateTimeTableTask(TimeTableTaskDTO dto)
					throws IllegalArgumentException {
		TimeTableTask timeTableTask;
		if (dto.getId()!=null)	{
			timeTableTask = pm.getObjectById(TimeTableTask.class, dto.getId());
			timeTableTask.update(dto);
		}
		else	{ 
			timeTableTask = new TimeTableTask(dto);
		}
		pm.makePersistent(timeTableTask);
		return timeTableTask.getId().toString();
	}
	public Integer countGoals(String frameOfMind)	throws IllegalArgumentException {
		Query query;
		query=pm.newQuery("SELECT count(id) FROM com.higgins.eventtracking.server.dataModel.Goal WHERE frameOfMind == \"" + frameOfMind + "\"");
		Integer list = (Integer) query.execute(frameOfMind);
		return list;
	}
	public List<GoalDTO> retrieveGoals(String frameOfMind)	throws IllegalArgumentException {
		List<GoalDTO> dtoResults = new ArrayList<GoalDTO>(); 
		List<Goal> results; 
		Query query;
		query=pm.newQuery(Goal.class);
		query.setFilter("frameOfMind == frameOfMindParam");
		query.declareParameters("String frameOfMindParam");
		query.setOrdering("order asc");
		results = (List<Goal>) query.execute(frameOfMind);
		
		for (Goal goal:results)	{
			dtoResults.add(goal.toDTO());
		}
		return dtoResults;
	}
	public String updateGoal(GoalDTO dto)	throws IllegalArgumentException {
		Goal goal;
		if (dto.getId()!=null)	{
			goal = pm.getObjectById(Goal.class, dto.getId());
			goal.update(dto);
		}	else	{ 
			goal = new Goal(dto);
		}
		pm.makePersistent(goal);
		return goal.getId().toString();
	}
	public List<HealthEventDTO> retrieveHealthEvents(String event)	throws IllegalArgumentException {
		List<HealthEventDTO> dtoResults = new ArrayList<HealthEventDTO>(); 
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType == eventTypeParam");
		query.declareParameters("String eventTypeParam");
		results = (List<HealthEvent>) query.execute(event);
		
		for (HealthEvent healthEvent:results)	{
			dtoResults.add(healthEvent.toDTO());
		}
		return dtoResults;
	}
	public List<HealthEventDTO> retrieveHealthEvents(String event, String eventTwo)	throws IllegalArgumentException {
		List<HealthEventDTO> dtoResults = new ArrayList<HealthEventDTO>(); 
		List<HealthEvent> results; 
		Query query;
		query=pm.newQuery(HealthEvent.class);
		query.setFilter("healthEventType == eventTypeParam || healthEventType == eventTypeParamTwo");
		query.declareParameters("String eventTypeParam, String eventTypeParamTwo");
		results = (List<HealthEvent>) query.execute(event, eventTwo);
		
		for (HealthEvent healthEvent:results)	{
			dtoResults.add(healthEvent.toDTO());
		}
		return dtoResults;
	}	
	public Long deleteGoal(Long id)	{
		Goal goal;
		if (id!=null)	{
			goal = pm.getObjectById(Goal.class, id);
			pm.deletePersistent(goal);
			return id;
		}
		return null;
	}
	public String completeGoal(GoalDTO dto)	{
		Goal goal;
		if (dto.getId()!=null)	{
//			javax.jdo.Transaction transaction = pm.currentTransaction();
//			transaction.begin();
			goal = pm.getObjectById(Goal.class, dto.getId());
			
			HealthEvent healthEvent = new HealthEvent();
			healthEvent.setHealthEventType("Achieve");
			healthEvent.setHealthEventIntensityScale(dto.getIntensity());
			healthEvent.setHealthEventFrameOfMind(dto.getFrameOfMind());
			healthEvent.setDescription(dto.getTask());
			healthEvent.setTimestamp(new Date());
			pm.makePersistent(healthEvent);
			pm.deletePersistent(goal);
//			transaction.commit();
			return "";
		}
		return null;
	}
	
	public List<SupportDTO> retrieveSupport()	throws IllegalArgumentException {
		List<SupportDTO> dtoResults = new ArrayList<SupportDTO>(); 
		List<Support> results; 
		Query query;
		query=pm.newQuery(Support.class);
		query.setOrdering("level, name desc");
		results = (List<Support>) query.execute();
		
		for (Support support:results)	{
			dtoResults.add(support.toDTO());
		}
		return dtoResults;
	}
	public String updateSupport(SupportDTO dto)	throws IllegalArgumentException {
		Support support;
		if (dto.getId()!=null)	{
			support = pm.getObjectById(Support.class, dto.getId());
			support.update(dto);
		}	else	{ 
			support = new Support(dto);
		}
		pm.makePersistent(support);
		return support.getId().toString();
	}	
	
	public Long deleteSupport(Long id)	{
		Support support;
		if (id!=null)	{
			support = pm.getObjectById(Support.class, id);
			pm.deletePersistent(support);
			return id;
		}
		return null;
	}
	
	public Double retrieveMaxWeightThisWeek(String exercise)	throws IllegalArgumentException	{
		Date now = new Date();
		Date start = getStartOfWeekDate(now).getTime();
		Query query;
//		query=pm.newQuery("SELECT max(weight) FROM com.higgins.eventtracking.server.dataModel.TrackingEvent WHERE eventType == \"" + exercise + "\"");
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("eventType == eventParam && timestamp > startDate && timestamp < endDate");
		query.declareParameters("String eventParam, java.util.Date startDate, java.util.Date endDate");
		List<Object> parameters = new ArrayList<Object>();
		parameters.add(exercise);
		parameters.add(start);
		parameters.add(now);
		List<TrackingEvent>results = (List<TrackingEvent>) query.executeWithArray(parameters.toArray());
		
		Collections.sort(results, new Comparator<TrackingEvent>(){
            public int compare(TrackingEvent s1,TrackingEvent s2){
            	return s2.getWeight().compareTo(s1.getWeight());
          }});
		if (results.size() > 0)
			return results.get(0).getWeight();
		return 0.0;
	}

	public Double retrieveMaxDistanceThisWeek(String exercise)	throws IllegalArgumentException	{
		Date now = new Date();
		Date start = getStartOfWeekDate(now).getTime();
		Query query;
		query=pm.newQuery(TrackingEvent.class);
		query.setFilter("eventType == eventParam && timestamp > startDate && timestamp < endDate");
		query.declareParameters("String eventParam, java.util.Date startDate, java.util.Date endDate");
		List<Object> parameters = new ArrayList<Object>();
		parameters.add(exercise);
		parameters.add(start);
		parameters.add(now);
		List<TrackingEvent>results = (List<TrackingEvent>) query.executeWithArray(parameters.toArray());
		
		Collections.sort(results, new Comparator<TrackingEvent>(){
            public int compare(TrackingEvent s1,TrackingEvent s2){
            	return s2.getDistance().compareTo(s1.getDistance());
          }});
		if (results.size() > 0)	{
			Double total = 0.0;
			for (TrackingEvent event:results)	{
				total = total + event.getDistance();
			}
			return total;
		}
		return 0.0;
	}	
	
	public List<RuleDTO> retrieveRules(String parentDynamicType, String frameOfMind)	throws IllegalArgumentException {
		List<RuleDTO> dtoResults = new ArrayList<RuleDTO>(); 
		List<Rule> results; 
		Query query;
		query=pm.newQuery(Rule.class);
		if (parentDynamicType!=null)  {
	        query.setFilter("frameOfMind == frameOfMindParam && parentDynamicType == parentDynamicTypeParam");
	        query.declareParameters("String frameOfMindParam, String parentDynamicTypeParam");
	        query.setOrdering("timestamp desc");
            results = (List<Rule>) query.execute(frameOfMind, parentDynamicType);
		} else {
    		query.setFilter("frameOfMind == frameOfMindParam");
    		query.declareParameters("String frameOfMindParam");
            query.setOrdering("timestamp desc");
            results = (List<Rule>) query.execute(frameOfMind);
    	}
		for (Rule rule:results)	{
			dtoResults.add(rule.toDTO());
		}
		return dtoResults;
	}
    public List<RuleDTO> retrieveRules(String parentDynamicType, String frameOfMind, Date startDate, Date endDate)    throws IllegalArgumentException {
        List<RuleDTO> dtoResults = new ArrayList<RuleDTO>(); 
        List<Rule> results; 
        Query query;
        List arguments = new ArrayList();
        query=pm.newQuery(Rule.class);
        if (parentDynamicType!=null)  {
            query.setFilter("frameOfMind == frameOfMindParam && parentDynamicType == parentDynamicTypeParam && timestamp > startDateParam && timestamp < endDateParam");
            query.declareParameters("String frameOfMindParam, String parentDynamicTypeParam, java.util.Date startDateParam, java.util.Date endDateParam");
            query.setOrdering("timestamp desc");
            Object[] parameters =  {frameOfMind, parentDynamicType, startDate, endDate};
            results = (List<Rule>) query.executeWithArray(parameters);
        } else {
            query.setFilter("frameOfMind == frameOfMindParam && timestamp > startDateParam && timestamp < endDateParam" );
            query.declareParameters("String frameOfMindParam, java.util.Date startDateParam, java.util.Date endDateParam");
            query.setOrdering("timestamp desc");
            Object[] parameters =  {frameOfMind, startDate, endDate};
            results = (List<Rule>) query.executeWithArray(parameters);
        }
        for (Rule rule:results) {
            dtoResults.add(rule.toDTO());
        }
        return dtoResults;
    }	
	public String updateRule(RuleDTO dto)	throws IllegalArgumentException {
		Rule rule;
		if (dto.getId()!=null)	{
			rule = pm.getObjectById(Rule.class, dto.getId());
			rule.update(dto);
		}	else	{ 
			rule = new Rule(dto);
		}
		pm.makePersistent(rule);
		return rule.getId().toString();
	}
	public Long deleteRule(Long id)	{
		Rule rule;
		if (id!=null)	{
			rule = pm.getObjectById(Rule.class, id);
			pm.deletePersistent(rule);
			return id;
		}
		return null;
	}
}
